Load libraries

# install.packages("plotly")
# install.packages("latex2exp")
# install.packages("BiocManager") 
# BiocManager::install("EBImage")
library(EBImage)

Attaching package: ‘EBImage’

The following object is masked from ‘package:purrr’:

    transpose
library(plotly)

Attaching package: ‘plotly’

The following object is masked from ‘package:EBImage’:

    toRGB

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout
library(ggplot2)
library(stringr)
library(latex2exp)

Attaching package: ‘latex2exp’

The following object is masked from ‘package:plotly’:

    TeX
packageVersion('plotly')
[1] ‘4.9.1’
Sys.setenv("plotly_username"="thuynh32")
Sys.setenv("plotly_api_key"="xcSv1yzujDc1IGEwQlr2")

Load data

# persons = c("01", "04", "05", "06", "07", "08", "10", "11", "12")
persons = c("01", "02", "03", "04", "05", "06", "07", "08", "09", "10",
            "12", "13", "15", "16", "17", "18",
            "22", "23", "24", "26", "28", "29", 
            "30", "31", "32", "41")

datas = vector(mode="list", length=length(persons))
datas_baseline = vector(mode="list", length=length(persons))
pp_means = vector(mode="list", length=length(persons))

names(datas) <- persons
names(datas_baseline) <- persons
names(pp_means) <- persons

for (p in persons) {
  datas[[p]] <- read.csv(str_interp("../../../data/TT1/preprocessed/T0${person}/T0${person}_Drive_4.csv", list(person=p)))
  datas_baseline[[p]] <- read.csv(str_interp("../../../data/TT1/preprocessed/T0${person}/T0${person}_Drive_1.csv", list(person=p)))
  
  # Compute the mean
  p_pp_nr <- datas_baseline[[p]]$Perspiration
  p_pp_nr <- p_pp_nr[!is.na(p_pp_nr)]
  pp_means[[p]] <- mean(p_pp_nr)
}

Merge PP Data

all <- data.frame()
all_baseline <- data.frame()
for (p in persons) {
  # On-road
  df_p <- datas[[p]]
  df_p$ppNormalized <- df_p$Perspiration - pp_means[[p]]
  df_p$ppLogNormalized <- log(df_p$Perspiration) - log(pp_means[[p]])
  df_p$Subject <- p
  
  all <- rbind(all, df_p)
  
  # Baseline
  df_p_baseline <- datas_baseline[[p]]
  df_p_baseline$Subject <- p
  all_baseline <- rbind(all_baseline, df_p_baseline)
}
print(length(all$Time))
[1] 2162
print(length(all_baseline$Time))
[1] 12454

Prepare the PP plots

vline <- function(x = 0, color = "red") {
  list(
    type = "line", 
    y0 = 0, 
    y1 = 1, 
    yref = "paper",
    x0 = x, 
    x1 = x, 
    line = list(color = color, dash="dot", width=1)
  )
}
hline <- function(y = 0, color = "blue") {
  list(
    type = "line", 
    x0 = 0, 
    x1 = 1, 
    xref = "paper",
    y0 = y, 
    y1 = y, 
    line = list(color = color, dash="dot", width=1)
  )
}

Draw all PP

plot_all_PP <- plot_ly(all, x = ~Time, y = ~Perspiration, name = ~Subject, 
                       type = 'scatter', mode = 'lines', width = 800, line=list(width=1.5),
                       color = ~Subject) %>% layout(title="", xaxis=list(title="Time [s]"), yaxis=list(title="Perspiration"))
htmltools::tagList(plot_all_PP)
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors

Draw all PP (Normalized with baseline mean)

plot_all_PP <- plot_ly(all, x = ~Time, y = ~ppNormalized, name = ~Subject, 
                       type = 'scatter', mode = 'lines', width = 800, line=list(width=1.5),
                       color = ~Subject) %>% layout(title="", xaxis=list(title="Time [s]"), yaxis=list(title="Normalized Perspiration"))
htmltools::tagList(plot_all_PP)
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors

Draw all Speed

plot_all_Speed <- plot_ly(all, x = ~Time, y = ~Speed, name = ~Subject, 
                       type = 'scatter', mode = 'lines', width = 800, line=list(width=1.5),
                       color = ~Subject) %>% layout(title="", xaxis=list(title="Time [s]"), yaxis=list(title="Speed"))
htmltools::tagList(plot_all_Speed)
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors

Draw all BR

# Because the BR affects to the PP
# What we wanna see here is if the Subject 01 is having higher BR than normal
mean_BR_All <- mean(all$BR)
argument is not numeric or logical: returning NA
mean_BR_P1 <- mean(all[all$Subject=='01',]$BR)
argument is not numeric or logical: returning NA
ant_All <- list(y = mean_BR_All, x = 100, text = "BR mean of all", color="blue")
plot_all_BR <- plot_ly(all, x = ~Time, y = ~Braking, name = ~Subject, 
                       type = 'scatter', mode = 'lines', width = 800, line=list(width=1.5),
                       color = ~Subject) %>% 
  layout(title="", xaxis=list(title="Time [s]"), yaxis=list(title="Breath Rate [BPM]"), 
         shapes=list(hline(mean_BR_All, color="blue")), 
         annotations=list(ant_All))
htmltools::tagList(plot_all_BR)
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors

Analyze Density

Configuration

EXP_COLORS <- c("#00AEDB", "#D11141")
QC_COLORS <- c("#00AEDB", "#D11141")

PP

data_PP <- all$Perspiration
data_PP <- data_PP[!is.na(data_PP) & data_PP >= 0.001 & data_PP <= 0.016]
data_PP_Baseline <- all_baseline$Perspiration
data_PP_Baseline <- data_PP_Baseline[!is.na(data_PP_Baseline) & data_PP_Baseline >= 0.001 & data_PP_Baseline <= 0.016]

mean_PP <- mean(data_PP)
mean_PP_Baseline <- mean(data_PP_Baseline)

df_PP <- data.frame(PP=data_PP)
df_PP_Baseline <- data.frame(PP=data_PP_Baseline)
df_PP$Experiment <- "On-Road Driving"
df_PP_Baseline$Experiment <- "Baseline"

df_PP_All <- rbind(df_PP, df_PP_Baseline)

plot_PP <- ggplot(df_PP_All, aes(PP, fill=Experiment)) + 
  geom_density(alpha = 0.3) + 
  labs(x = "Perspiration", y = "PDF") + 
  geom_vline(xintercept=mean_PP, linetype="dashed", color=EXP_COLORS[2]) + 
  geom_vline(xintercept=mean_PP_Baseline, linetype="dashed", color=EXP_COLORS[1]) + 
  annotate(geom="text", x=mean_PP_Baseline - 0.00015, y=600, label=paste0("Baseline Mean = ", round(mean_PP_Baseline, 4)), color="blue", angle=90, size=3) +
  annotate(geom="text", x=mean_PP - 0.00015, y=600, label=paste0("ORD Mean = ", round(mean_PP, 4)), color="red", angle=90, size=3, vjust=0) +
  scale_fill_manual(values=EXP_COLORS)
# plot_PP <- ggplotly(plot_PP)
# htmltools::tagList(plot_PP)
print(plot_PP)

PP - Baseline

data_PP_Norm <- all$ppNormalized
data_PP_Norm <- data_PP_Norm[!is.na(data_PP_Norm) & data_PP_Norm >= -0.016 & data_PP_Norm <= 0.016]

mean_PP_Norm <- mean(data_PP_Norm)
threshold_PP_Norm <- mean(data_PP_Norm)

mat_PP_Norm <- matrix(data_PP_Norm,nrow = 1,ncol = length(data_PP_Norm))
threshold_PP_Norm <- otsu(mat_PP_Norm, range=c(min(data_PP_Norm), max(data_PP_Norm)))

df_PP_Norm <- data.frame(PP=data_PP_Norm)
df_PP_Norm$Experiment <- "On-Road Driving"

plot_PP_Norm <- ggplot(df_PP_Norm, aes(PP, fill=Experiment)) + 
  geom_density(alpha = 0.3) + 
  labs(x = TeX("$PP_{OnRoad} - PP_{Baseline}$"), y = "PDF") + 
  theme(legend.position = "none") + 
  geom_vline(xintercept=mean_PP_Norm, linetype="dashed", color="blue") + 
  geom_vline(xintercept=0, linetype="dashed", color="darkgray") + 
  geom_vline(xintercept=threshold_PP_Norm, linetype="dashed", color="red") + 
  annotate(geom="text", x=mean_PP_Norm - 0.00015, y=550, label=paste0("Mean = ", round(mean_PP_Norm, 4)), color="blue", angle=90, size=3) +
  annotate(geom="text", x=0 - 0.00015, y=50, label="Baseline", color="black", angle=90, size=3, vjust=0) +
  annotate(geom="text", x=threshold_PP_Norm - 0.00015, y=550, label=paste0("Threshold = ", round(threshold_PP_Norm, 4)), color="red", angle=90, size=3, vjust=0) +
  scale_fill_manual(values=rev(EXP_COLORS))
#plot_PP_Norm <- ggplotly(plot_PP_Norm)
#htmltools::tagList(plot_PP_Norm)
print(plot_PP_Norm)

log(PP - Baseline)

data_PP_Norm <- all$ppLogNormalized
data_PP_Norm <- data_PP_Norm[!is.na(data_PP_Norm)]

mean_PP_Norm <- mean(data_PP_Norm)
threshold_PP_Norm <- mean(data_PP_Norm)

mat_PP_Norm <- matrix(data_PP_Norm,nrow = 1,ncol = length(data_PP_Norm))
threshold_PP_Norm <- otsu(mat_PP_Norm, range=c(min(data_PP_Norm), max(data_PP_Norm)))

df_PP_Norm <- data.frame(PP=data_PP_Norm)
df_PP_Norm$Experiment <- "On-Road Driving"

plot_PP_Norm <- ggplot(df_PP_Norm, aes(PP, fill=Experiment)) + 
  geom_density(alpha = 0.3) + 
  labs(x = TeX("All Subjects: $\\textit{log}(PP_{OnRoad}) - \\textit{log}(PP_{Baseline})$"), y = "PDF") + 
  theme(legend.position = "none") + 
  geom_vline(xintercept=mean_PP_Norm, linetype="dashed", color="blue") + 
  geom_vline(xintercept=0, linetype="dashed", color="darkgray") + 
  geom_vline(xintercept=threshold_PP_Norm, linetype="dashed", color="red") + 
  annotate(geom="text", x=mean_PP_Norm - 0.025, y=2, label=paste0("Mean = ", round(mean_PP_Norm, 4)), color="blue", angle=90, size=3) +
  annotate(geom="text", x=0 - 0.015, y=2, label="Baseline", color="black", angle=90, size=3, vjust=0) +
  annotate(geom="text", x=threshold_PP_Norm - 0.015, y=2, label=paste0("Threshold = ", round(threshold_PP_Norm, 4)), color="red", angle=90, size=3, vjust=0) +
  scale_fill_manual(values=rev(EXP_COLORS))
#plot_PP_Norm <- ggplotly(plot_PP_Norm)
#htmltools::tagList(plot_PP_Norm)
print(plot_PP_Norm)

Heart Rate

data_HR <- all$HR
data_HR <- data_HR[!is.na(data_HR)]
data_HR_QC1 <- data_HR[(data_HR >= 40) & (data_HR <= 140)]

mean_HR <- mean(data_HR)
argument is not numeric or logical: returning NA
mean_HR_QC1 <- mean(data_HR_QC1)
argument is not numeric or logical: returning NA
df_HR <- data.frame(HR=data_HR)
df_HR_QC1 <- data.frame(HR=data_HR_QC1)
df_HR$Type <- "Before QC1"
Error in `$<-.data.frame`(`*tmp*`, Type, value = "Before QC1") : 
  replacement has 1 row, data has 0

Breath Rate

data_BR <- all$BR
data_BR <- data_BR[!is.na(data_BR)]
data_BR_QC1 <- data_BR[data_BR >= 4 & data_BR <= 40]

mean_BR <- mean(data_BR)
argument is not numeric or logical: returning NA
mean_BR_QC1 <- mean(data_BR_QC1)
argument is not numeric or logical: returning NA
df_BR <- data.frame(BR=data_BR)
df_BR_QC1 <- data.frame(BR=data_BR_QC1)
df_BR$Type <- "Before QC1"
Error in `$<-.data.frame`(`*tmp*`, Type, value = "Before QC1") : 
  replacement has 1 row, data has 0

Brake

data_Brake <- all$Braking
data_Brake <- data_Brake[!is.na(data_Brake)]

mean_Brake <- mean(data_Brake)

df_Brake <- data.frame(Brake=data_Brake)
df_Brake$Type <- "Brake [%]"

mat_Brake <- matrix(data_Brake,nrow = 1,ncol = length(data_Brake))
threshold_Brake <- otsu(mat_Brake, range=c(min(data_Brake), max(data_Brake)))

plot_Brake <- ggplot(df_Brake, aes(Brake, fill=Type)) + 
  geom_density(alpha = 0.3) + 
  labs(x = "Brake [%]", y = "PDF") + 
  geom_vline(xintercept=mean_Brake, linetype="dashed", color="blue") +  
  geom_vline(xintercept=threshold_Brake, linetype="dashed", color="red") + 
  annotate(geom="text", x=threshold_Brake - 1, y=0.05, label=paste0("Threshold = ", round(threshold_Brake, 2)), color="red", angle=90, size=3, vjust=0) + 
  annotate(geom="text", x=mean_Brake - 1, y=0.05, label=paste0("Mean = ", round(mean_Brake, 2)), color="blue", angle=90, size=3, vjust=0) + 
  scale_fill_manual(values=rev(QC_COLORS))
# plot_Brake <- ggplotly(plot_Brake)
# htmltools::tagList(plot_Brake)
print(plot_Brake)

Speed

data_Speed <- all$Speed
data_Speed <- data_Speed[!is.na(data_Speed)]

mean_Speed <- mean(data_Speed)

df_Speed <- data.frame(Speed=data_Speed)
df_Speed$Type <- "Speed [km/h]"

mat_Speed <- matrix(data_Speed,nrow = 1,ncol = length(data_Speed))
threshold_Speed <- otsu(mat_Speed, range=c(min(data_Speed), max(data_Speed)))
adj_Threshold_Speed <- 15

plot_Speed <- ggplot(df_Speed, aes(Speed, fill=Type)) + 
  geom_density(alpha = 0.3) + 
  labs(x = "Speed [km/h]", y = "PDF") + 
  geom_vline(xintercept=mean_Speed, linetype="dashed", color="blue") + 
  geom_vline(xintercept=threshold_Speed, linetype="dashed", color="red") + 
  geom_vline(xintercept=adj_Threshold_Speed, linetype="dashed", color="purple") + 
  annotate(geom="text", x=threshold_Speed - 2, y=0.02, label=paste0("Threshold = ", round(threshold_Speed, 2)), color="red", angle=90, size=3) + 
  annotate(geom="text", x=adj_Threshold_Speed - 2, y=0.02, label=paste0("Adj. Threshold = ", round(adj_Threshold_Speed, 2)), color="purple", angle=90, size=3) + 
  annotate(geom="text", x=mean_Speed + 2, y=0.02, label=paste0("Mean = ", round(mean_Speed, 2)), color="blue", angle=90, size=3) + 
  scale_fill_manual(values=rev(QC_COLORS))
# plot_Speed <- ggplotly(plot_Speed)
# htmltools::tagList(plot_Speed)

print(plot_Speed)

Accelerator


data_Accelerator <- all$Acceleration
data_Accelerator <- data_Accelerator[!is.na(data_Accelerator)]

mean_Accelerator <- mean(data_Accelerator)

df_Accelerator <- data.frame(Accelerator=data_Accelerator)
df_Accelerator$Type <- "Acceleration [%]"

mat_Accelerator <- matrix(data_Accelerator,nrow = 1,ncol = length(data_Accelerator))
threshold_Accelerator <- 8.5 # otsu(mat_Accelerator, range=c(min(data_Accelerator), max(data_Accelerator)))

plot_Accelerator <- ggplot(df_Accelerator, aes(Accelerator, fill=Type)) + 
  geom_density(alpha = 0.3) + 
  labs(x = "Accelerator [%]", y = "PDF") + 
  geom_vline(xintercept=mean_Accelerator, linetype="dashed", color="blue") + 
  geom_vline(xintercept=threshold_Accelerator, linetype="dashed", color="red") + 
  annotate(geom="text", x=mean_Accelerator - 0.5, y=0.05, label=paste0("Mean = ", round(mean_Accelerator, 2)), color="blue", angle=90, size=3, vjust=0) + 
  annotate(geom="text", x=threshold_Accelerator - 0.5, y=0.05, label=paste0("Threshold = ", round(threshold_Accelerator, 2)), color="red", angle=90, size=3, vjust=0) + 
  scale_fill_manual(values=rev(QC_COLORS))

# plot_Accelerator <- ggplotly(plot_Accelerator)
# htmltools::tagList(plot_Accelerator)
print(plot_Accelerator)

Steering


data_Steering <- all$Steering
data_Steering <- data_Steering[!is.na(data_Steering) & abs(data_Steering) < 500]
data_Steering_QC1 <- data_Steering[abs(data_Steering) <= 360]

mean_Steering <- mean(data_Steering)
mean_Steering_QC1 <- mean(data_Steering_QC1)

df_Steering <- data.frame(Steering=data_Steering)
df_Steering_QC1 <- data.frame(Steering=data_Steering_QC1)
df_Steering$Type <- "Before QC1"
df_Steering_QC1$Type <- "After QC1"

df_Steering_All <- rbind(df_Steering, df_Steering_QC1)

plot_Steering <- ggplot(df_Steering_All, aes(Steering, fill=Type)) + 
  geom_density(alpha = 0.3) + 
  labs(x = "Steering [Degree]", y = "PDF") + 
  geom_vline(xintercept=mean_Steering, linetype="dashed", color=QC_COLORS[2]) + 
  geom_vline(xintercept=mean_Steering_QC1, linetype="dashed", color=QC_COLORS[1]) + 
  scale_fill_manual(values=QC_COLORS)
# plot_Steering <- ggplotly(plot_Steering)
# htmltools::tagList(plot_Steering)

print(plot_Steering)

Map

Sys.setenv('MAPBOX_TOKEN' = 'pk.eyJ1IjoidGh1eW5oMzIiLCJhIjoiY2p6endwbXY3MjJ0cTNtbWwzN3E0enZuciJ9.fpzzkDjWHb0LOcTog8B6Lg')
MAP_MODE_COLORS <- c("#7c91f5", "#ea4335")

all$IN_Lat_Degree <- all$IN_Lat / 60
all$IN_Long_Degree <- all$IN_Long / 60
mapCenter <- list(lat = mean(all$IN_Lat_Degree), lon = mean(all$IN_Long_Degree))

Map of Speed

all$cls_Speed <- ifelse(all$Speed > threshold_Speed, "High Speed", "Low Speed")
all$diff_Speed <- abs(all$Speed - threshold_Speed)
pMap_Speed <- all %>% plot_mapbox(lat=~IN_Lat_Degree, lon=~IN_Long_Degree, split=~cls_Speed, size=~diff_Speed, mode = 'scattermapbox', hoverinfo='text', text=~Subject, alpha = 1, opacity=0.1, height=600) %>%
              layout(title = 'Speeding spots',
                     legend = list(orientation = 'h', font = list(size = 8)),
                     colorway=rev(MAP_MODE_COLORS),
                     mapbox = list(zoom = 12, center = mapCenter))
htmltools::tagList(pMap_Speed)

Map of Accelerator

all$cls_Accel <- ifelse(all$Accelerator > threshold_Accelerator, "High Acceleration", "Low Acceleration")
pMap_Accel <- all %>% plot_mapbox(lat=~IN_Lat_Degree, lon=~IN_Long_Degree, split=~cls_Accel, size=~Accelerator, height=600,
              mode = 'scattermapbox', hoverinfo='text', text=~Subject, alpha = 1, opacity=0.1) %>%
              layout(title = 'Acceleration spots',
                     legend = list(orientation = 'h', font = list(size = 8)),
                     colorway=rev(MAP_MODE_COLORS),
                     mapbox = list(zoom = 12, center = center))
htmltools::tagList(pMap_Accel)

Map of Brake

all$cls_Brake <- ifelse(all$Brake > threshold_Brake, "High Brake", "Low Brake")
all_Brake <- all[order(all$cls_Brake, decreasing = F),]
pMap_Brake <- all_Brake %>% plot_mapbox(lat=~IN_Lat_Degree, lon=~IN_Long_Degree, split=~cls_Brake, size=~Brake, height=600,
              mode = 'scattermapbox', hoverinfo='text', text=~Subject, alpha = 1, opacity=0.1) %>%
              layout(title = 'Brake spots',
                     legend = list(orientation = 'h', font = list(size = 8)),
                     colorway=rev(MAP_MODE_COLORS),
                     mapbox = list(zoom = 12, center = center))
htmltools::tagList(pMap_Brake)

Map of PP

all$cls_PP <- ifelse(!is.na(all$ppNormalized) & all$ppNormalized >= threshold_PP_Norm, "High PP", "Low PP")
all_PP <- all[order(all$cls_PP, decreasing = F),]
pMap_PP <- all_PP %>% plot_mapbox(lat=~IN_Lat_Degree, lon=~IN_Long_Degree, split=~cls_PP, size=~ppNormalized, height=600,
              mode = 'scattermapbox', hoverinfo='text', text=~paste(Subject, ": ", ppNormalized), alpha = 1, opacity=0.1) %>%
              layout(title = 'PP spots',
                     legend = list(orientation = 'h', font = list(size = 8)),
                     colorway=rev(MAP_MODE_COLORS),
                     mapbox = list(zoom = 12, center = center))
htmltools::tagList(pMap_PP)
LS0tCnRpdGxlOiAiRGF0YSBNZXJnZSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMgTG9hZCBsaWJyYXJpZXMKYGBge3J9CiMgaW5zdGFsbC5wYWNrYWdlcygicGxvdGx5IikKIyBpbnN0YWxsLnBhY2thZ2VzKCJsYXRleDJleHAiKQojIGluc3RhbGwucGFja2FnZXMoIkJpb2NNYW5hZ2VyIikgCiMgQmlvY01hbmFnZXI6Omluc3RhbGwoIkVCSW1hZ2UiKQpsaWJyYXJ5KEVCSW1hZ2UpCmxpYnJhcnkocGxvdGx5KQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShsYXRleDJleHApCnBhY2thZ2VWZXJzaW9uKCdwbG90bHknKQpTeXMuc2V0ZW52KCJwbG90bHlfdXNlcm5hbWUiPSJ0aHV5bmgzMiIpClN5cy5zZXRlbnYoInBsb3RseV9hcGlfa2V5Ij0ieGNTdjF5enVqRGMxSUdFd1FscjIiKQpgYGAKCiMjIExvYWQgZGF0YQpgYGB7cn0KIyBwZXJzb25zID0gYygiMDEiLCAiMDQiLCAiMDUiLCAiMDYiLCAiMDciLCAiMDgiLCAiMTAiLCAiMTEiLCAiMTIiKQpwZXJzb25zID0gYygiMDEiLCAiMDIiLCAiMDMiLCAiMDQiLCAiMDUiLCAiMDYiLCAiMDciLCAiMDgiLCAiMDkiLCAiMTAiLAogICAgICAgICAgICAiMTIiLCAiMTMiLCAiMTUiLCAiMTYiLCAiMTciLCAiMTgiLAogICAgICAgICAgICAiMjIiLCAiMjMiLCAiMjQiLCAiMjYiLCAiMjgiLCAiMjkiLCAKICAgICAgICAgICAgIjMwIiwgIjMxIiwgIjMyIiwgIjQxIikKCmRhdGFzID0gdmVjdG9yKG1vZGU9Imxpc3QiLCBsZW5ndGg9bGVuZ3RoKHBlcnNvbnMpKQpkYXRhc19iYXNlbGluZSA9IHZlY3Rvcihtb2RlPSJsaXN0IiwgbGVuZ3RoPWxlbmd0aChwZXJzb25zKSkKcHBfbWVhbnMgPSB2ZWN0b3IobW9kZT0ibGlzdCIsIGxlbmd0aD1sZW5ndGgocGVyc29ucykpCgpuYW1lcyhkYXRhcykgPC0gcGVyc29ucwpuYW1lcyhkYXRhc19iYXNlbGluZSkgPC0gcGVyc29ucwpuYW1lcyhwcF9tZWFucykgPC0gcGVyc29ucwoKZm9yIChwIGluIHBlcnNvbnMpIHsKICBkYXRhc1tbcF1dIDwtIHJlYWQuY3N2KHN0cl9pbnRlcnAoIi4uLy4uLy4uL2RhdGEvVFQxL3ByZXByb2Nlc3NlZC9UMCR7cGVyc29ufS9UMCR7cGVyc29ufV9Ecml2ZV80LmNzdiIsIGxpc3QocGVyc29uPXApKSkKICBkYXRhc19iYXNlbGluZVtbcF1dIDwtIHJlYWQuY3N2KHN0cl9pbnRlcnAoIi4uLy4uLy4uL2RhdGEvVFQxL3ByZXByb2Nlc3NlZC9UMCR7cGVyc29ufS9UMCR7cGVyc29ufV9Ecml2ZV8xLmNzdiIsIGxpc3QocGVyc29uPXApKSkKICAKICAjIENvbXB1dGUgdGhlIG1lYW4KICBwX3BwX25yIDwtIGRhdGFzX2Jhc2VsaW5lW1twXV0kUGVyc3BpcmF0aW9uCiAgcF9wcF9uciA8LSBwX3BwX25yWyFpcy5uYShwX3BwX25yKV0KICBwcF9tZWFuc1tbcF1dIDwtIG1lYW4ocF9wcF9ucikKfQpgYGAKCiMjIyBNZXJnZSBQUCBEYXRhCmBgYHtyfQphbGwgPC0gZGF0YS5mcmFtZSgpCmFsbF9iYXNlbGluZSA8LSBkYXRhLmZyYW1lKCkKZm9yIChwIGluIHBlcnNvbnMpIHsKICAjIE9uLXJvYWQKICBkZl9wIDwtIGRhdGFzW1twXV0KICBkZl9wJHBwTm9ybWFsaXplZCA8LSBkZl9wJFBlcnNwaXJhdGlvbiAtIHBwX21lYW5zW1twXV0KICBkZl9wJHBwTG9nTm9ybWFsaXplZCA8LSBsb2coZGZfcCRQZXJzcGlyYXRpb24pIC0gbG9nKHBwX21lYW5zW1twXV0pCiAgZGZfcCRTdWJqZWN0IDwtIHAKICAKICBhbGwgPC0gcmJpbmQoYWxsLCBkZl9wKQogIAogICMgQmFzZWxpbmUKICBkZl9wX2Jhc2VsaW5lIDwtIGRhdGFzX2Jhc2VsaW5lW1twXV0KICBkZl9wX2Jhc2VsaW5lJFN1YmplY3QgPC0gcAogIGFsbF9iYXNlbGluZSA8LSByYmluZChhbGxfYmFzZWxpbmUsIGRmX3BfYmFzZWxpbmUpCn0KcHJpbnQobGVuZ3RoKGFsbCRUaW1lKSkKcHJpbnQobGVuZ3RoKGFsbF9iYXNlbGluZSRUaW1lKSkKYGBgCiMjIFByZXBhcmUgdGhlIFBQIHBsb3RzCmBgYHtyfQp2bGluZSA8LSBmdW5jdGlvbih4ID0gMCwgY29sb3IgPSAicmVkIikgewogIGxpc3QoCiAgICB0eXBlID0gImxpbmUiLCAKICAgIHkwID0gMCwgCiAgICB5MSA9IDEsIAogICAgeXJlZiA9ICJwYXBlciIsCiAgICB4MCA9IHgsIAogICAgeDEgPSB4LCAKICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gY29sb3IsIGRhc2g9ImRvdCIsIHdpZHRoPTEpCiAgKQp9CmhsaW5lIDwtIGZ1bmN0aW9uKHkgPSAwLCBjb2xvciA9ICJibHVlIikgewogIGxpc3QoCiAgICB0eXBlID0gImxpbmUiLCAKICAgIHgwID0gMCwgCiAgICB4MSA9IDEsIAogICAgeHJlZiA9ICJwYXBlciIsCiAgICB5MCA9IHksIAogICAgeTEgPSB5LCAKICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gY29sb3IsIGRhc2g9ImRvdCIsIHdpZHRoPTEpCiAgKQp9CmBgYAoKIyMjIERyYXcgYWxsIFBQCmBgYHtyfQpwbG90X2FsbF9QUCA8LSBwbG90X2x5KGFsbCwgeCA9IH5UaW1lLCB5ID0gflBlcnNwaXJhdGlvbiwgbmFtZSA9IH5TdWJqZWN0LCAKICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzJywgd2lkdGggPSA4MDAsIGxpbmU9bGlzdCh3aWR0aD0xLjUpLAogICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gflN1YmplY3QpICU+JSBsYXlvdXQodGl0bGU9IiIsIHhheGlzPWxpc3QodGl0bGU9IlRpbWUgW3NdIiksIHlheGlzPWxpc3QodGl0bGU9IlBlcnNwaXJhdGlvbiIpKQpodG1sdG9vbHM6OnRhZ0xpc3QocGxvdF9hbGxfUFApCmBgYAojIyMgRHJhdyBhbGwgUFAgKE5vcm1hbGl6ZWQgd2l0aCBiYXNlbGluZSBtZWFuKQpgYGB7cn0KcGxvdF9hbGxfUFAgPC0gcGxvdF9seShhbGwsIHggPSB+VGltZSwgeSA9IH5wcE5vcm1hbGl6ZWQsIG5hbWUgPSB+U3ViamVjdCwgCiAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcycsIHdpZHRoID0gODAwLCBsaW5lPWxpc3Qod2lkdGg9MS41KSwKICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IH5TdWJqZWN0KSAlPiUgbGF5b3V0KHRpdGxlPSIiLCB4YXhpcz1saXN0KHRpdGxlPSJUaW1lIFtzXSIpLCB5YXhpcz1saXN0KHRpdGxlPSJOb3JtYWxpemVkIFBlcnNwaXJhdGlvbiIpKQpodG1sdG9vbHM6OnRhZ0xpc3QocGxvdF9hbGxfUFApCmBgYAoKIyMjIERyYXcgYWxsIFNwZWVkCmBgYHtyfQpwbG90X2FsbF9TcGVlZCA8LSBwbG90X2x5KGFsbCwgeCA9IH5UaW1lLCB5ID0gflNwZWVkLCBuYW1lID0gflN1YmplY3QsIAogICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMnLCB3aWR0aCA9IDgwMCwgbGluZT1saXN0KHdpZHRoPTEuNSksCiAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+U3ViamVjdCkgJT4lIGxheW91dCh0aXRsZT0iIiwgeGF4aXM9bGlzdCh0aXRsZT0iVGltZSBbc10iKSwgeWF4aXM9bGlzdCh0aXRsZT0iU3BlZWQiKSkKaHRtbHRvb2xzOjp0YWdMaXN0KHBsb3RfYWxsX1NwZWVkKQpgYGAKCiMjIyBEcmF3IGFsbCBCUgpgYGB7cn0KIyBCZWNhdXNlIHRoZSBCUiBhZmZlY3RzIHRvIHRoZSBQUAojIFdoYXQgd2Ugd2FubmEgc2VlIGhlcmUgaXMgaWYgdGhlIFN1YmplY3QgMDEgaXMgaGF2aW5nIGhpZ2hlciBCUiB0aGFuIG5vcm1hbAptZWFuX0JSX0FsbCA8LSBtZWFuKGFsbCRCUikKbWVhbl9CUl9QMSA8LSBtZWFuKGFsbFthbGwkU3ViamVjdD09JzAxJyxdJEJSKQoKYW50X0FsbCA8LSBsaXN0KHkgPSBtZWFuX0JSX0FsbCwgeCA9IDEwMCwgdGV4dCA9ICJCUiBtZWFuIG9mIGFsbCIsIGNvbG9yPSJibHVlIikKcGxvdF9hbGxfQlIgPC0gcGxvdF9seShhbGwsIHggPSB+VGltZSwgeSA9IH5CcmFraW5nLCBuYW1lID0gflN1YmplY3QsIAogICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMnLCB3aWR0aCA9IDgwMCwgbGluZT1saXN0KHdpZHRoPTEuNSksCiAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+U3ViamVjdCkgJT4lIAogIGxheW91dCh0aXRsZT0iIiwgeGF4aXM9bGlzdCh0aXRsZT0iVGltZSBbc10iKSwgeWF4aXM9bGlzdCh0aXRsZT0iQnJlYXRoIFJhdGUgW0JQTV0iKSwgCiAgICAgICAgIHNoYXBlcz1saXN0KGhsaW5lKG1lYW5fQlJfQWxsLCBjb2xvcj0iYmx1ZSIpKSwgCiAgICAgICAgIGFubm90YXRpb25zPWxpc3QoYW50X0FsbCkpCmh0bWx0b29sczo6dGFnTGlzdChwbG90X2FsbF9CUikKYGBgCgoKIyMgQW5hbHl6ZSBEZW5zaXR5CiMjIENvbmZpZ3VyYXRpb24KYGBge3J9CkVYUF9DT0xPUlMgPC0gYygiIzAwQUVEQiIsICIjRDExMTQxIikKUUNfQ09MT1JTIDwtIGMoIiMwMEFFREIiLCAiI0QxMTE0MSIpCmBgYAoKCiMjIyBQUApgYGB7cn0KZGF0YV9QUCA8LSBhbGwkUGVyc3BpcmF0aW9uCmRhdGFfUFAgPC0gZGF0YV9QUFshaXMubmEoZGF0YV9QUCkgJiBkYXRhX1BQID49IDAuMDAxICYgZGF0YV9QUCA8PSAwLjAxNl0KZGF0YV9QUF9CYXNlbGluZSA8LSBhbGxfYmFzZWxpbmUkUGVyc3BpcmF0aW9uCmRhdGFfUFBfQmFzZWxpbmUgPC0gZGF0YV9QUF9CYXNlbGluZVshaXMubmEoZGF0YV9QUF9CYXNlbGluZSkgJiBkYXRhX1BQX0Jhc2VsaW5lID49IDAuMDAxICYgZGF0YV9QUF9CYXNlbGluZSA8PSAwLjAxNl0KCm1lYW5fUFAgPC0gbWVhbihkYXRhX1BQKQptZWFuX1BQX0Jhc2VsaW5lIDwtIG1lYW4oZGF0YV9QUF9CYXNlbGluZSkKCmRmX1BQIDwtIGRhdGEuZnJhbWUoUFA9ZGF0YV9QUCkKZGZfUFBfQmFzZWxpbmUgPC0gZGF0YS5mcmFtZShQUD1kYXRhX1BQX0Jhc2VsaW5lKQpkZl9QUCRFeHBlcmltZW50IDwtICJPbi1Sb2FkIERyaXZpbmciCmRmX1BQX0Jhc2VsaW5lJEV4cGVyaW1lbnQgPC0gIkJhc2VsaW5lIgoKZGZfUFBfQWxsIDwtIHJiaW5kKGRmX1BQLCBkZl9QUF9CYXNlbGluZSkKCnBsb3RfUFAgPC0gZ2dwbG90KGRmX1BQX0FsbCwgYWVzKFBQLCBmaWxsPUV4cGVyaW1lbnQpKSArIAogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuMykgKyAKICBsYWJzKHggPSAiUGVyc3BpcmF0aW9uIiwgeSA9ICJQREYiKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdD1tZWFuX1BQLCBsaW5ldHlwZT0iZGFzaGVkIiwgY29sb3I9RVhQX0NPTE9SU1syXSkgKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9bWVhbl9QUF9CYXNlbGluZSwgbGluZXR5cGU9ImRhc2hlZCIsIGNvbG9yPUVYUF9DT0xPUlNbMV0pICsgCiAgYW5ub3RhdGUoZ2VvbT0idGV4dCIsIHg9bWVhbl9QUF9CYXNlbGluZSAtIDAuMDAwMTUsIHk9NjAwLCBsYWJlbD1wYXN0ZTAoIkJhc2VsaW5lIE1lYW4gPSAiLCByb3VuZChtZWFuX1BQX0Jhc2VsaW5lLCA0KSksIGNvbG9yPSJibHVlIiwgYW5nbGU9OTAsIHNpemU9MykgKwogIGFubm90YXRlKGdlb209InRleHQiLCB4PW1lYW5fUFAgLSAwLjAwMDE1LCB5PTYwMCwgbGFiZWw9cGFzdGUwKCJPUkQgTWVhbiA9ICIsIHJvdW5kKG1lYW5fUFAsIDQpKSwgY29sb3I9InJlZCIsIGFuZ2xlPTkwLCBzaXplPTMsIHZqdXN0PTApICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9RVhQX0NPTE9SUykKIyBwbG90X1BQIDwtIGdncGxvdGx5KHBsb3RfUFApCiMgaHRtbHRvb2xzOjp0YWdMaXN0KHBsb3RfUFApCnByaW50KHBsb3RfUFApCmBgYAoKIyMjIFBQIC0gQmFzZWxpbmUKYGBge3J9CmRhdGFfUFBfTm9ybSA8LSBhbGwkcHBOb3JtYWxpemVkCmRhdGFfUFBfTm9ybSA8LSBkYXRhX1BQX05vcm1bIWlzLm5hKGRhdGFfUFBfTm9ybSkgJiBkYXRhX1BQX05vcm0gPj0gLTAuMDE2ICYgZGF0YV9QUF9Ob3JtIDw9IDAuMDE2XQoKbWVhbl9QUF9Ob3JtIDwtIG1lYW4oZGF0YV9QUF9Ob3JtKQp0aHJlc2hvbGRfUFBfTm9ybSA8LSBtZWFuKGRhdGFfUFBfTm9ybSkKCm1hdF9QUF9Ob3JtIDwtIG1hdHJpeChkYXRhX1BQX05vcm0sbnJvdyA9IDEsbmNvbCA9IGxlbmd0aChkYXRhX1BQX05vcm0pKQp0aHJlc2hvbGRfUFBfTm9ybSA8LSBvdHN1KG1hdF9QUF9Ob3JtLCByYW5nZT1jKG1pbihkYXRhX1BQX05vcm0pLCBtYXgoZGF0YV9QUF9Ob3JtKSkpCgpkZl9QUF9Ob3JtIDwtIGRhdGEuZnJhbWUoUFA9ZGF0YV9QUF9Ob3JtKQpkZl9QUF9Ob3JtJEV4cGVyaW1lbnQgPC0gIk9uLVJvYWQgRHJpdmluZyIKCnBsb3RfUFBfTm9ybSA8LSBnZ3Bsb3QoZGZfUFBfTm9ybSwgYWVzKFBQLCBmaWxsPUV4cGVyaW1lbnQpKSArIAogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuMykgKyAKICBsYWJzKHggPSBUZVgoIiRQUF97T25Sb2FkfSAtIFBQX3tCYXNlbGluZX0kIiksIHkgPSAiUERGIikgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PW1lYW5fUFBfTm9ybSwgbGluZXR5cGU9ImRhc2hlZCIsIGNvbG9yPSJibHVlIikgKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9MCwgbGluZXR5cGU9ImRhc2hlZCIsIGNvbG9yPSJkYXJrZ3JheSIpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PXRocmVzaG9sZF9QUF9Ob3JtLCBsaW5ldHlwZT0iZGFzaGVkIiwgY29sb3I9InJlZCIpICsgCiAgYW5ub3RhdGUoZ2VvbT0idGV4dCIsIHg9bWVhbl9QUF9Ob3JtIC0gMC4wMDAxNSwgeT01NTAsIGxhYmVsPXBhc3RlMCgiTWVhbiA9ICIsIHJvdW5kKG1lYW5fUFBfTm9ybSwgNCkpLCBjb2xvcj0iYmx1ZSIsIGFuZ2xlPTkwLCBzaXplPTMpICsKICBhbm5vdGF0ZShnZW9tPSJ0ZXh0IiwgeD0wIC0gMC4wMDAxNSwgeT01MCwgbGFiZWw9IkJhc2VsaW5lIiwgY29sb3I9ImJsYWNrIiwgYW5nbGU9OTAsIHNpemU9Mywgdmp1c3Q9MCkgKwogIGFubm90YXRlKGdlb209InRleHQiLCB4PXRocmVzaG9sZF9QUF9Ob3JtIC0gMC4wMDAxNSwgeT01NTAsIGxhYmVsPXBhc3RlMCgiVGhyZXNob2xkID0gIiwgcm91bmQodGhyZXNob2xkX1BQX05vcm0sIDQpKSwgY29sb3I9InJlZCIsIGFuZ2xlPTkwLCBzaXplPTMsIHZqdXN0PTApICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9cmV2KEVYUF9DT0xPUlMpKQojcGxvdF9QUF9Ob3JtIDwtIGdncGxvdGx5KHBsb3RfUFBfTm9ybSkKI2h0bWx0b29sczo6dGFnTGlzdChwbG90X1BQX05vcm0pCnByaW50KHBsb3RfUFBfTm9ybSkKYGBgCgoKIyMjIGxvZyhQUCAtIEJhc2VsaW5lKQpgYGB7cn0KZGF0YV9QUF9Ob3JtIDwtIGFsbCRwcExvZ05vcm1hbGl6ZWQKZGF0YV9QUF9Ob3JtIDwtIGRhdGFfUFBfTm9ybVshaXMubmEoZGF0YV9QUF9Ob3JtKV0KCm1lYW5fUFBfTm9ybSA8LSBtZWFuKGRhdGFfUFBfTm9ybSkKdGhyZXNob2xkX1BQX05vcm0gPC0gbWVhbihkYXRhX1BQX05vcm0pCgptYXRfUFBfTm9ybSA8LSBtYXRyaXgoZGF0YV9QUF9Ob3JtLG5yb3cgPSAxLG5jb2wgPSBsZW5ndGgoZGF0YV9QUF9Ob3JtKSkKdGhyZXNob2xkX1BQX05vcm0gPC0gb3RzdShtYXRfUFBfTm9ybSwgcmFuZ2U9YyhtaW4oZGF0YV9QUF9Ob3JtKSwgbWF4KGRhdGFfUFBfTm9ybSkpKQoKZGZfUFBfTm9ybSA8LSBkYXRhLmZyYW1lKFBQPWRhdGFfUFBfTm9ybSkKZGZfUFBfTm9ybSRFeHBlcmltZW50IDwtICJPbi1Sb2FkIERyaXZpbmciCgpwbG90X1BQX05vcm0gPC0gZ2dwbG90KGRmX1BQX05vcm0sIGFlcyhQUCwgZmlsbD1FeHBlcmltZW50KSkgKyAKICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjMpICsgCiAgbGFicyh4ID0gVGVYKCJBbGwgU3ViamVjdHM6ICRcXHRleHRpdHtsb2d9KFBQX3tPblJvYWR9KSAtIFxcdGV4dGl0e2xvZ30oUFBfe0Jhc2VsaW5lfSkkIiksIHkgPSAiUERGIikgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PW1lYW5fUFBfTm9ybSwgbGluZXR5cGU9ImRhc2hlZCIsIGNvbG9yPSJibHVlIikgKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9MCwgbGluZXR5cGU9ImRhc2hlZCIsIGNvbG9yPSJkYXJrZ3JheSIpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PXRocmVzaG9sZF9QUF9Ob3JtLCBsaW5ldHlwZT0iZGFzaGVkIiwgY29sb3I9InJlZCIpICsgCiAgYW5ub3RhdGUoZ2VvbT0idGV4dCIsIHg9bWVhbl9QUF9Ob3JtIC0gMC4wMjUsIHk9MiwgbGFiZWw9cGFzdGUwKCJNZWFuID0gIiwgcm91bmQobWVhbl9QUF9Ob3JtLCA0KSksIGNvbG9yPSJibHVlIiwgYW5nbGU9OTAsIHNpemU9MykgKwogIGFubm90YXRlKGdlb209InRleHQiLCB4PTAgLSAwLjAxNSwgeT0yLCBsYWJlbD0iQmFzZWxpbmUiLCBjb2xvcj0iYmxhY2siLCBhbmdsZT05MCwgc2l6ZT0zLCB2anVzdD0wKSArCiAgYW5ub3RhdGUoZ2VvbT0idGV4dCIsIHg9dGhyZXNob2xkX1BQX05vcm0gLSAwLjAxNSwgeT0yLCBsYWJlbD1wYXN0ZTAoIlRocmVzaG9sZCA9ICIsIHJvdW5kKHRocmVzaG9sZF9QUF9Ob3JtLCA0KSksIGNvbG9yPSJyZWQiLCBhbmdsZT05MCwgc2l6ZT0zLCB2anVzdD0wKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPXJldihFWFBfQ09MT1JTKSkKI3Bsb3RfUFBfTm9ybSA8LSBnZ3Bsb3RseShwbG90X1BQX05vcm0pCiNodG1sdG9vbHM6OnRhZ0xpc3QocGxvdF9QUF9Ob3JtKQpwcmludChwbG90X1BQX05vcm0pCmBgYAoKIyMjIEhlYXJ0IFJhdGUKYGBge3J9CmRhdGFfSFIgPC0gYWxsJEhSCmRhdGFfSFIgPC0gZGF0YV9IUlshaXMubmEoZGF0YV9IUildCmRhdGFfSFJfUUMxIDwtIGRhdGFfSFJbKGRhdGFfSFIgPj0gNDApICYgKGRhdGFfSFIgPD0gMTQwKV0KCm1lYW5fSFIgPC0gbWVhbihkYXRhX0hSKQptZWFuX0hSX1FDMSA8LSBtZWFuKGRhdGFfSFJfUUMxKQoKZGZfSFIgPC0gZGF0YS5mcmFtZShIUj1kYXRhX0hSKQpkZl9IUl9RQzEgPC0gZGF0YS5mcmFtZShIUj1kYXRhX0hSX1FDMSkKZGZfSFIkVHlwZSA8LSAiQmVmb3JlIFFDMSIKZGZfSFJfUUMxJFR5cGUgPC0gIkFmdGVyIFFDMSIKCmRmX0hSX0FsbCA8LSByYmluZChkZl9IUiwgZGZfSFJfUUMxKQoKcGxvdF9IUiA8LSBnZ3Bsb3QoZGZfSFJfQWxsLCBhZXMoSFIsIGZpbGw9VHlwZSkpICsgCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC4zKSArIAogIGxhYnMoeCA9ICJIUiBbQlBNXSIsIHkgPSAiUERGIikgKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9bWVhbl9IUiwgbGluZXR5cGU9ImRhc2hlZCIsIGNvbG9yPVFDX0NPTE9SU1syXSkgKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9bWVhbl9IUl9RQzEsIGxpbmV0eXBlPSJkYXNoZWQiLCBjb2xvcj1RQ19DT0xPUlNbMV0pICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPVFDX0NPTE9SUykKIyBwbG90X0hSIDwtIGdncGxvdGx5KHBsb3RfSFIpCiMgaHRtbHRvb2xzOjp0YWdMaXN0KHBsb3RfSFIpCnByaW50KHBsb3RfSFIpCmBgYAojIyMgQnJlYXRoIFJhdGUKYGBge3J9CmRhdGFfQlIgPC0gYWxsJEJSCmRhdGFfQlIgPC0gZGF0YV9CUlshaXMubmEoZGF0YV9CUildCmRhdGFfQlJfUUMxIDwtIGRhdGFfQlJbZGF0YV9CUiA+PSA0ICYgZGF0YV9CUiA8PSA0MF0KCm1lYW5fQlIgPC0gbWVhbihkYXRhX0JSKQptZWFuX0JSX1FDMSA8LSBtZWFuKGRhdGFfQlJfUUMxKQoKZGZfQlIgPC0gZGF0YS5mcmFtZShCUj1kYXRhX0JSKQpkZl9CUl9RQzEgPC0gZGF0YS5mcmFtZShCUj1kYXRhX0JSX1FDMSkKZGZfQlIkVHlwZSA8LSAiQmVmb3JlIFFDMSIKZGZfQlJfUUMxJFR5cGUgPC0gIkFmdGVyIFFDMSIKCmRmX0JSX0FsbCA8LSByYmluZChkZl9CUiwgZGZfQlJfUUMxKQoKcGxvdF9CUiA8LSBnZ3Bsb3QoZGZfQlJfQWxsLCBhZXMoQlIsIGZpbGw9VHlwZSkpICsgCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC4zKSArIAogIGxhYnMoeCA9ICJCUiBbQlBNXSIsIHkgPSAiUERGIikgKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9bWVhbl9CUiwgbGluZXR5cGU9ImRhc2hlZCIsIGNvbG9yPVFDX0NPTE9SU1syXSkgKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9bWVhbl9CUl9RQzEsIGxpbmV0eXBlPSJkYXNoZWQiLCBjb2xvcj1RQ19DT0xPUlNbMV0pICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPVFDX0NPTE9SUykKIyBwbG90X0JSIDwtIGdncGxvdGx5KHBsb3RfQlIpCiMgaHRtbHRvb2xzOjp0YWdMaXN0KHBsb3RfQlIpCnByaW50KHBsb3RfQlIpCmBgYAoKIyMjIEJyYWtlCmBgYHtyfQpkYXRhX0JyYWtlIDwtIGFsbCRCcmFraW5nCmRhdGFfQnJha2UgPC0gZGF0YV9CcmFrZVshaXMubmEoZGF0YV9CcmFrZSldCgptZWFuX0JyYWtlIDwtIG1lYW4oZGF0YV9CcmFrZSkKCmRmX0JyYWtlIDwtIGRhdGEuZnJhbWUoQnJha2U9ZGF0YV9CcmFrZSkKZGZfQnJha2UkVHlwZSA8LSAiQnJha2UgWyVdIgoKbWF0X0JyYWtlIDwtIG1hdHJpeChkYXRhX0JyYWtlLG5yb3cgPSAxLG5jb2wgPSBsZW5ndGgoZGF0YV9CcmFrZSkpCnRocmVzaG9sZF9CcmFrZSA8LSBvdHN1KG1hdF9CcmFrZSwgcmFuZ2U9YyhtaW4oZGF0YV9CcmFrZSksIG1heChkYXRhX0JyYWtlKSkpCgpwbG90X0JyYWtlIDwtIGdncGxvdChkZl9CcmFrZSwgYWVzKEJyYWtlLCBmaWxsPVR5cGUpKSArIAogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuMykgKyAKICBsYWJzKHggPSAiQnJha2UgWyVdIiwgeSA9ICJQREYiKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdD1tZWFuX0JyYWtlLCBsaW5ldHlwZT0iZGFzaGVkIiwgY29sb3I9ImJsdWUiKSArICAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9dGhyZXNob2xkX0JyYWtlLCBsaW5ldHlwZT0iZGFzaGVkIiwgY29sb3I9InJlZCIpICsgCiAgYW5ub3RhdGUoZ2VvbT0idGV4dCIsIHg9dGhyZXNob2xkX0JyYWtlIC0gMSwgeT0wLjA1LCBsYWJlbD1wYXN0ZTAoIlRocmVzaG9sZCA9ICIsIHJvdW5kKHRocmVzaG9sZF9CcmFrZSwgMikpLCBjb2xvcj0icmVkIiwgYW5nbGU9OTAsIHNpemU9Mywgdmp1c3Q9MCkgKyAKICBhbm5vdGF0ZShnZW9tPSJ0ZXh0IiwgeD1tZWFuX0JyYWtlIC0gMSwgeT0wLjA1LCBsYWJlbD1wYXN0ZTAoIk1lYW4gPSAiLCByb3VuZChtZWFuX0JyYWtlLCAyKSksIGNvbG9yPSJibHVlIiwgYW5nbGU9OTAsIHNpemU9Mywgdmp1c3Q9MCkgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9cmV2KFFDX0NPTE9SUykpCiMgcGxvdF9CcmFrZSA8LSBnZ3Bsb3RseShwbG90X0JyYWtlKQojIGh0bWx0b29sczo6dGFnTGlzdChwbG90X0JyYWtlKQpwcmludChwbG90X0JyYWtlKQpgYGAKCiMjIyBTcGVlZApgYGB7cn0KZGF0YV9TcGVlZCA8LSBhbGwkU3BlZWQKZGF0YV9TcGVlZCA8LSBkYXRhX1NwZWVkWyFpcy5uYShkYXRhX1NwZWVkKV0KCm1lYW5fU3BlZWQgPC0gbWVhbihkYXRhX1NwZWVkKQoKZGZfU3BlZWQgPC0gZGF0YS5mcmFtZShTcGVlZD1kYXRhX1NwZWVkKQpkZl9TcGVlZCRUeXBlIDwtICJTcGVlZCBba20vaF0iCgptYXRfU3BlZWQgPC0gbWF0cml4KGRhdGFfU3BlZWQsbnJvdyA9IDEsbmNvbCA9IGxlbmd0aChkYXRhX1NwZWVkKSkKdGhyZXNob2xkX1NwZWVkIDwtIG90c3UobWF0X1NwZWVkLCByYW5nZT1jKG1pbihkYXRhX1NwZWVkKSwgbWF4KGRhdGFfU3BlZWQpKSkKYWRqX1RocmVzaG9sZF9TcGVlZCA8LSAxNQoKcGxvdF9TcGVlZCA8LSBnZ3Bsb3QoZGZfU3BlZWQsIGFlcyhTcGVlZCwgZmlsbD1UeXBlKSkgKyAKICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjMpICsgCiAgbGFicyh4ID0gIlNwZWVkIFtrbS9oXSIsIHkgPSAiUERGIikgKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9bWVhbl9TcGVlZCwgbGluZXR5cGU9ImRhc2hlZCIsIGNvbG9yPSJibHVlIikgKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9dGhyZXNob2xkX1NwZWVkLCBsaW5ldHlwZT0iZGFzaGVkIiwgY29sb3I9InJlZCIpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PWFkal9UaHJlc2hvbGRfU3BlZWQsIGxpbmV0eXBlPSJkYXNoZWQiLCBjb2xvcj0icHVycGxlIikgKyAKICBhbm5vdGF0ZShnZW9tPSJ0ZXh0IiwgeD10aHJlc2hvbGRfU3BlZWQgLSAyLCB5PTAuMDIsIGxhYmVsPXBhc3RlMCgiVGhyZXNob2xkID0gIiwgcm91bmQodGhyZXNob2xkX1NwZWVkLCAyKSksIGNvbG9yPSJyZWQiLCBhbmdsZT05MCwgc2l6ZT0zKSArIAogIGFubm90YXRlKGdlb209InRleHQiLCB4PWFkal9UaHJlc2hvbGRfU3BlZWQgLSAyLCB5PTAuMDIsIGxhYmVsPXBhc3RlMCgiQWRqLiBUaHJlc2hvbGQgPSAiLCByb3VuZChhZGpfVGhyZXNob2xkX1NwZWVkLCAyKSksIGNvbG9yPSJwdXJwbGUiLCBhbmdsZT05MCwgc2l6ZT0zKSArIAogIGFubm90YXRlKGdlb209InRleHQiLCB4PW1lYW5fU3BlZWQgKyAyLCB5PTAuMDIsIGxhYmVsPXBhc3RlMCgiTWVhbiA9ICIsIHJvdW5kKG1lYW5fU3BlZWQsIDIpKSwgY29sb3I9ImJsdWUiLCBhbmdsZT05MCwgc2l6ZT0zKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1yZXYoUUNfQ09MT1JTKSkKIyBwbG90X1NwZWVkIDwtIGdncGxvdGx5KHBsb3RfU3BlZWQpCiMgaHRtbHRvb2xzOjp0YWdMaXN0KHBsb3RfU3BlZWQpCgpwcmludChwbG90X1NwZWVkKQpgYGAKCiMjIyBBY2NlbGVyYXRvcgpgYGB7cn0KCmRhdGFfQWNjZWxlcmF0b3IgPC0gYWxsJEFjY2VsZXJhdGlvbgpkYXRhX0FjY2VsZXJhdG9yIDwtIGRhdGFfQWNjZWxlcmF0b3JbIWlzLm5hKGRhdGFfQWNjZWxlcmF0b3IpXQoKbWVhbl9BY2NlbGVyYXRvciA8LSBtZWFuKGRhdGFfQWNjZWxlcmF0b3IpCgpkZl9BY2NlbGVyYXRvciA8LSBkYXRhLmZyYW1lKEFjY2VsZXJhdG9yPWRhdGFfQWNjZWxlcmF0b3IpCmRmX0FjY2VsZXJhdG9yJFR5cGUgPC0gIkFjY2VsZXJhdGlvbiBbJV0iCgptYXRfQWNjZWxlcmF0b3IgPC0gbWF0cml4KGRhdGFfQWNjZWxlcmF0b3IsbnJvdyA9IDEsbmNvbCA9IGxlbmd0aChkYXRhX0FjY2VsZXJhdG9yKSkKdGhyZXNob2xkX0FjY2VsZXJhdG9yIDwtIDguNSAjIG90c3UobWF0X0FjY2VsZXJhdG9yLCByYW5nZT1jKG1pbihkYXRhX0FjY2VsZXJhdG9yKSwgbWF4KGRhdGFfQWNjZWxlcmF0b3IpKSkKCnBsb3RfQWNjZWxlcmF0b3IgPC0gZ2dwbG90KGRmX0FjY2VsZXJhdG9yLCBhZXMoQWNjZWxlcmF0b3IsIGZpbGw9VHlwZSkpICsgCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC4zKSArIAogIGxhYnMoeCA9ICJBY2NlbGVyYXRvciBbJV0iLCB5ID0gIlBERiIpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PW1lYW5fQWNjZWxlcmF0b3IsIGxpbmV0eXBlPSJkYXNoZWQiLCBjb2xvcj0iYmx1ZSIpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PXRocmVzaG9sZF9BY2NlbGVyYXRvciwgbGluZXR5cGU9ImRhc2hlZCIsIGNvbG9yPSJyZWQiKSArIAogIGFubm90YXRlKGdlb209InRleHQiLCB4PW1lYW5fQWNjZWxlcmF0b3IgLSAwLjUsIHk9MC4wNSwgbGFiZWw9cGFzdGUwKCJNZWFuID0gIiwgcm91bmQobWVhbl9BY2NlbGVyYXRvciwgMikpLCBjb2xvcj0iYmx1ZSIsIGFuZ2xlPTkwLCBzaXplPTMsIHZqdXN0PTApICsgCiAgYW5ub3RhdGUoZ2VvbT0idGV4dCIsIHg9dGhyZXNob2xkX0FjY2VsZXJhdG9yIC0gMC41LCB5PTAuMDUsIGxhYmVsPXBhc3RlMCgiVGhyZXNob2xkID0gIiwgcm91bmQodGhyZXNob2xkX0FjY2VsZXJhdG9yLCAyKSksIGNvbG9yPSJyZWQiLCBhbmdsZT05MCwgc2l6ZT0zLCB2anVzdD0wKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1yZXYoUUNfQ09MT1JTKSkKCiMgcGxvdF9BY2NlbGVyYXRvciA8LSBnZ3Bsb3RseShwbG90X0FjY2VsZXJhdG9yKQojIGh0bWx0b29sczo6dGFnTGlzdChwbG90X0FjY2VsZXJhdG9yKQpwcmludChwbG90X0FjY2VsZXJhdG9yKQpgYGAKCiMjIyBTdGVlcmluZwpgYGB7cn0KCmRhdGFfU3RlZXJpbmcgPC0gYWxsJFN0ZWVyaW5nCmRhdGFfU3RlZXJpbmcgPC0gZGF0YV9TdGVlcmluZ1shaXMubmEoZGF0YV9TdGVlcmluZykgJiBhYnMoZGF0YV9TdGVlcmluZykgPCA1MDBdCmRhdGFfU3RlZXJpbmdfUUMxIDwtIGRhdGFfU3RlZXJpbmdbYWJzKGRhdGFfU3RlZXJpbmcpIDw9IDM2MF0KCm1lYW5fU3RlZXJpbmcgPC0gbWVhbihkYXRhX1N0ZWVyaW5nKQptZWFuX1N0ZWVyaW5nX1FDMSA8LSBtZWFuKGRhdGFfU3RlZXJpbmdfUUMxKQoKZGZfU3RlZXJpbmcgPC0gZGF0YS5mcmFtZShTdGVlcmluZz1kYXRhX1N0ZWVyaW5nKQpkZl9TdGVlcmluZ19RQzEgPC0gZGF0YS5mcmFtZShTdGVlcmluZz1kYXRhX1N0ZWVyaW5nX1FDMSkKZGZfU3RlZXJpbmckVHlwZSA8LSAiQmVmb3JlIFFDMSIKZGZfU3RlZXJpbmdfUUMxJFR5cGUgPC0gIkFmdGVyIFFDMSIKCmRmX1N0ZWVyaW5nX0FsbCA8LSByYmluZChkZl9TdGVlcmluZywgZGZfU3RlZXJpbmdfUUMxKQoKcGxvdF9TdGVlcmluZyA8LSBnZ3Bsb3QoZGZfU3RlZXJpbmdfQWxsLCBhZXMoU3RlZXJpbmcsIGZpbGw9VHlwZSkpICsgCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC4zKSArIAogIGxhYnMoeCA9ICJTdGVlcmluZyBbRGVncmVlXSIsIHkgPSAiUERGIikgKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9bWVhbl9TdGVlcmluZywgbGluZXR5cGU9ImRhc2hlZCIsIGNvbG9yPVFDX0NPTE9SU1syXSkgKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9bWVhbl9TdGVlcmluZ19RQzEsIGxpbmV0eXBlPSJkYXNoZWQiLCBjb2xvcj1RQ19DT0xPUlNbMV0pICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPVFDX0NPTE9SUykKIyBwbG90X1N0ZWVyaW5nIDwtIGdncGxvdGx5KHBsb3RfU3RlZXJpbmcpCiMgaHRtbHRvb2xzOjp0YWdMaXN0KHBsb3RfU3RlZXJpbmcpCgpwcmludChwbG90X1N0ZWVyaW5nKQpgYGAKCgojIyBNYXAKYGBge3J9ClN5cy5zZXRlbnYoJ01BUEJPWF9UT0tFTicgPSAncGsuZXlKMUlqb2lkR2gxZVc1b016SWlMQ0poSWpvaVkycDZlbmR3YlhZM01qSjBjVE50Yld3ek4zRTBlblp1Y2lKOS5mcHp6a0RqV0hiMExPY1RvZzhCNkxnJykKTUFQX01PREVfQ09MT1JTIDwtIGMoIiM3YzkxZjUiLCAiI2VhNDMzNSIpCgphbGwkSU5fTGF0X0RlZ3JlZSA8LSBhbGwkSU5fTGF0IC8gNjAKYWxsJElOX0xvbmdfRGVncmVlIDwtIGFsbCRJTl9Mb25nIC8gNjAKbWFwQ2VudGVyIDwtIGxpc3QobGF0ID0gbWVhbihhbGwkSU5fTGF0X0RlZ3JlZSksIGxvbiA9IG1lYW4oYWxsJElOX0xvbmdfRGVncmVlKSkKYGBgCgojIyMgTWFwIG9mIFNwZWVkCmBgYHtyIHdhcm5pbmc9RkFMU0V9CmFsbCRjbHNfU3BlZWQgPC0gaWZlbHNlKGFsbCRTcGVlZCA+IHRocmVzaG9sZF9TcGVlZCwgIkhpZ2ggU3BlZWQiLCAiTG93IFNwZWVkIikKYWxsJGRpZmZfU3BlZWQgPC0gYWJzKGFsbCRTcGVlZCAtIHRocmVzaG9sZF9TcGVlZCkKcE1hcF9TcGVlZCA8LSBhbGwgJT4lIHBsb3RfbWFwYm94KGxhdD1+SU5fTGF0X0RlZ3JlZSwgbG9uPX5JTl9Mb25nX0RlZ3JlZSwgc3BsaXQ9fmNsc19TcGVlZCwgc2l6ZT1+ZGlmZl9TcGVlZCwgbW9kZSA9ICdzY2F0dGVybWFwYm94JywgaG92ZXJpbmZvPSd0ZXh0JywgdGV4dD1+U3ViamVjdCwgYWxwaGEgPSAxLCBvcGFjaXR5PTAuMSwgaGVpZ2h0PTYwMCkgJT4lCiAgICAgICAgICAgICAgbGF5b3V0KHRpdGxlID0gJ1NwZWVkaW5nIHNwb3RzJywKICAgICAgICAgICAgICAgICAgICAgbGVnZW5kID0gbGlzdChvcmllbnRhdGlvbiA9ICdoJywgZm9udCA9IGxpc3Qoc2l6ZSA9IDgpKSwKICAgICAgICAgICAgICAgICAgICAgY29sb3J3YXk9cmV2KE1BUF9NT0RFX0NPTE9SUyksCiAgICAgICAgICAgICAgICAgICAgIG1hcGJveCA9IGxpc3Qoem9vbSA9IDEyLCBjZW50ZXIgPSBtYXBDZW50ZXIpKQpodG1sdG9vbHM6OnRhZ0xpc3QocE1hcF9TcGVlZCkKYGBgCiMjIyBNYXAgb2YgQWNjZWxlcmF0b3IKYGBge3Igd2FybmluZz1GQUxTRX0KYWxsJGNsc19BY2NlbCA8LSBpZmVsc2UoYWxsJEFjY2VsZXJhdG9yID4gdGhyZXNob2xkX0FjY2VsZXJhdG9yLCAiSGlnaCBBY2NlbGVyYXRpb24iLCAiTG93IEFjY2VsZXJhdGlvbiIpCnBNYXBfQWNjZWwgPC0gYWxsICU+JSBwbG90X21hcGJveChsYXQ9fklOX0xhdF9EZWdyZWUsIGxvbj1+SU5fTG9uZ19EZWdyZWUsIHNwbGl0PX5jbHNfQWNjZWwsIHNpemU9fkFjY2VsZXJhdG9yLCBoZWlnaHQ9NjAwLAogICAgICAgICAgICAgIG1vZGUgPSAnc2NhdHRlcm1hcGJveCcsIGhvdmVyaW5mbz0ndGV4dCcsIHRleHQ9flN1YmplY3QsIGFscGhhID0gMSwgb3BhY2l0eT0wLjEpICU+JQogICAgICAgICAgICAgIGxheW91dCh0aXRsZSA9ICdBY2NlbGVyYXRpb24gc3BvdHMnLAogICAgICAgICAgICAgICAgICAgICBsZWdlbmQgPSBsaXN0KG9yaWVudGF0aW9uID0gJ2gnLCBmb250ID0gbGlzdChzaXplID0gOCkpLAogICAgICAgICAgICAgICAgICAgICBjb2xvcndheT1yZXYoTUFQX01PREVfQ09MT1JTKSwKICAgICAgICAgICAgICAgICAgICAgbWFwYm94ID0gbGlzdCh6b29tID0gMTIsIGNlbnRlciA9IGNlbnRlcikpCmh0bWx0b29sczo6dGFnTGlzdChwTWFwX0FjY2VsKQpgYGAKCiMjIyBNYXAgb2YgQnJha2UKYGBge3Igd2FybmluZz1GQUxTRX0KYWxsJGNsc19CcmFrZSA8LSBpZmVsc2UoYWxsJEJyYWtlID4gdGhyZXNob2xkX0JyYWtlLCAiSGlnaCBCcmFrZSIsICJMb3cgQnJha2UiKQphbGxfQnJha2UgPC0gYWxsW29yZGVyKGFsbCRjbHNfQnJha2UsIGRlY3JlYXNpbmcgPSBGKSxdCnBNYXBfQnJha2UgPC0gYWxsX0JyYWtlICU+JSBwbG90X21hcGJveChsYXQ9fklOX0xhdF9EZWdyZWUsIGxvbj1+SU5fTG9uZ19EZWdyZWUsIHNwbGl0PX5jbHNfQnJha2UsIHNpemU9fkJyYWtlLCBoZWlnaHQ9NjAwLAogICAgICAgICAgICAgIG1vZGUgPSAnc2NhdHRlcm1hcGJveCcsIGhvdmVyaW5mbz0ndGV4dCcsIHRleHQ9flN1YmplY3QsIGFscGhhID0gMSwgb3BhY2l0eT0wLjEpICU+JQogICAgICAgICAgICAgIGxheW91dCh0aXRsZSA9ICdCcmFrZSBzcG90cycsCiAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZCA9IGxpc3Qob3JpZW50YXRpb24gPSAnaCcsIGZvbnQgPSBsaXN0KHNpemUgPSA4KSksCiAgICAgICAgICAgICAgICAgICAgIGNvbG9yd2F5PXJldihNQVBfTU9ERV9DT0xPUlMpLAogICAgICAgICAgICAgICAgICAgICBtYXBib3ggPSBsaXN0KHpvb20gPSAxMiwgY2VudGVyID0gY2VudGVyKSkKaHRtbHRvb2xzOjp0YWdMaXN0KHBNYXBfQnJha2UpCmBgYAoKIyMjIE1hcCBvZiBQUApgYGB7ciB3YXJuaW5nPUZBTFNFfQphbGwkY2xzX1BQIDwtIGlmZWxzZSghaXMubmEoYWxsJHBwTm9ybWFsaXplZCkgJiBhbGwkcHBOb3JtYWxpemVkID49IHRocmVzaG9sZF9QUF9Ob3JtLCAiSGlnaCBQUCIsICJMb3cgUFAiKQphbGxfUFAgPC0gYWxsW29yZGVyKGFsbCRjbHNfUFAsIGRlY3JlYXNpbmcgPSBGKSxdCnBNYXBfUFAgPC0gYWxsX1BQICU+JSBwbG90X21hcGJveChsYXQ9fklOX0xhdF9EZWdyZWUsIGxvbj1+SU5fTG9uZ19EZWdyZWUsIHNwbGl0PX5jbHNfUFAsIHNpemU9fnBwTm9ybWFsaXplZCwgaGVpZ2h0PTYwMCwKICAgICAgICAgICAgICBtb2RlID0gJ3NjYXR0ZXJtYXBib3gnLCBob3ZlcmluZm89J3RleHQnLCB0ZXh0PX5wYXN0ZShTdWJqZWN0LCAiOiAiLCBwcE5vcm1hbGl6ZWQpLCBhbHBoYSA9IDEsIG9wYWNpdHk9MC4xKSAlPiUKICAgICAgICAgICAgICBsYXlvdXQodGl0bGUgPSAnUFAgc3BvdHMnLAogICAgICAgICAgICAgICAgICAgICBsZWdlbmQgPSBsaXN0KG9yaWVudGF0aW9uID0gJ2gnLCBmb250ID0gbGlzdChzaXplID0gOCkpLAogICAgICAgICAgICAgICAgICAgICBjb2xvcndheT1yZXYoTUFQX01PREVfQ09MT1JTKSwKICAgICAgICAgICAgICAgICAgICAgbWFwYm94ID0gbGlzdCh6b29tID0gMTIsIGNlbnRlciA9IGNlbnRlcikpCmh0bWx0b29sczo6dGFnTGlzdChwTWFwX1BQKQpgYGAKCgo=